﻿#include "PropertyEditView.h"
#include "PropertyEditViewUi.h"

#include "LumDebug.h"
#include "ObjectSelector.h"
#include "EditEntry.h"
#include "ObjectPropertyEditEntryFactory.h"

#include "ObjectPropertyEditEntry.h"

#include "BoxLayoutPropertyEditEntry.h"
#include "FormLayoutPropertyEditEntry.h"
#include "GridLayoutPropertyEditEntry.h"
#include "StackedLayoutPropertyEditEntry.h"

#include "WidgetPropertyEditEntry.h"
#include "AbstractButtonPropertyEditEntry.h"

#include <QTimer>
#include <QElapsedTimer>

QMetaObject getMetaObject(QObject *object) {
    return *(object->metaObject());
}

struct PropertyEditView::PropertyEditorData {
    QList<QPointer<EditEntry>> entryList;
    QList<QPointer<PropertyEditEntry>> propertyEditEntryList;
};

PropertyEditView::~PropertyEditView() { }

PropertyEditView::PropertyEditView(QWidget *parent) : QWidget(parent) {
    p.reset(new PropertyEditorData);
    ui.reset(new PropertyEditViewUi);
    ui->SetupUI(this);

    setStyleSheet(R"(
        QWidget {
            font-family: Consolas;
            font-size: 14px;
        }
    )");

    ObjectSelector::instance()->excludeObject(this);
}

void PropertyEditView::editObject(QPointer<QObject> object) {
    QElapsedTimer counter;
    counter.start();
    const auto &description = QString("%1:%2").arg(object->objectName()).arg(object->metaObject()->className());
    ui->labelObjectInfo->setText(description);

    QList<const QMetaObject*> metaObjectHierarchy;

    const QMetaObject *metaObject = object->metaObject();
    while(metaObject != nullptr) {
        metaObjectHierarchy.prepend(metaObject);
        metaObject = metaObject->superClass();
    }

    while(ui->layoutEditors->count() > 0) {
        const auto item = ui->layoutEditors->itemAt(0);
        ui->layoutEditors->removeItem(item);
        if(const auto widget = item->widget()) {
            widget->setParent(nullptr);
            widget->hide();
        }
    }
    p->entryList.clear();
    p->propertyEditEntryList.clear();

    for(const auto &metaObject : metaObjectHierarchy) {
        //DEBUG << object->metaObject()->className() << metaObject->className() << object->objectName();
        const auto &entryList = ObjectPropertyEditEntryFactory::instance().createEditEntries(*metaObject, object.data());
        for(const auto entry : entryList) {
            appendPropertyEditEntry(entry);
        }
    }

    QTimer::singleShot(0, this, &PropertyEditView::onEntryExpandedOrCollapsed);
    ui->layoutEditors->addStretch();
    DEBUG << QString("Edit loading const %1 ms").arg(counter.elapsed());
}

void PropertyEditView::resizeEvent(QResizeEvent *event) {
    QWidget::resizeEvent(event);
    if(width() < 256) {
        ui->headerSplitter->setSizes({64, width()-64});
    } else {
        const int nameAreaWidth = 64 + (256-64) * width() / 1920.0;
        ui->headerSplitter->setSizes({nameAreaWidth, width()-nameAreaWidth});
    }
}

QList<QPointer<EditEntry>> getAllEntry(EditEntry *box) {
    QList<QPointer<EditEntry>> entryList;
    entryList.append(box);
    for(const auto entry : box->childEntries()) {
        entryList.append(getAllEntry(entry));
    }
    return entryList;
}

bool isPropertyEditEntry(EditEntry *box) {
    return box->inherits("PropertyEditEntry");
}

PropertyEditEntry *getPropertyEntry(EditEntry *box) {
    if(isPropertyEditEntry(box)) {
        return qobject_cast<PropertyEditEntry*>(box);
    }

    if(box->parentBox()) {
        return getPropertyEntry(box->parentBox());
    } else {
        return nullptr;
    }
}

void PropertyEditView::appendPropertyEditEntry(PropertyEditEntry *entry) {
    ui->layoutEditors->addWidget(entry);
    const auto addedEntryList = getAllEntry(entry);
    //DEBUG << entry->title() << addedEntryList.count();
    p->entryList.append(addedEntryList);
    p->propertyEditEntryList.append(entry);
    for(const auto entryElem : addedEntryList) {
        entryElem->setEditView(this);
        connect(entryElem, &EditEntry::expandedOrCollapsed, this, &PropertyEditView::onEntryExpandedOrCollapsed);
    }
}

QList<int> PropertyEditView::headerSizes() {
    return ui->headerSplitter->sizes();
}

void PropertyEditView::onCurrentChanged(QPointer<QObject> current, const QPointer<QObject> previous) {
    //DEBUG;
    if(!current) {
        return ;
    }
    editObject(current);
}

void PropertyEditView::onEntryExpandedOrCollapsed() {
    static QList<QColor> darkColorArray;
    static QList<QColor> lightColorArray;
    if(darkColorArray.isEmpty()) {
        const auto addColor = [=](const QColor &dark, const QColor &light) {
            darkColorArray.append(dark);
            lightColorArray.append(light);
        };
        addColor(QColor("#F5DEB3"), QColor("#FFF2DE"));
        addColor(QColor("#FFFFBF"), QColor("#FFFFDE")) ;
        addColor(QColor("#BFFFBF"), QColor("#DEFFDE"));
        addColor(QColor("#C7FFFF"), QColor("#E6FFFF"));
        addColor(QColor("#EABFFF"), QColor("#F4DEFF"));
        addColor(QColor("#FFBFEF"), QColor("#FFDEF7"));
        addColor(QColor("#FFE6BF"), QColor("#FFF2DE"));
    }

    int index = 0;
    for(const auto entry : p->entryList) {
        if(!entry->isVisible()) {
            continue;
        }

        if(!isPropertyEditEntry(entry)) {
            const auto propertyEditEntry = getPropertyEntry(entry);
            //DEBUG << QString("PropertyEditEntry of %1 is %2").arg(entry->title()).arg(propertyEditEntry->title());
            int propertyEntryIndex = p->propertyEditEntryList.indexOf(propertyEditEntry);
            const auto &color = index %2 == 0 ? darkColorArray.at(propertyEntryIndex) : lightColorArray.at(propertyEntryIndex);
            entry->setEditPanelBackground(color);
        }
        ++ index;
    }
}

void PropertyEditView::onHeaderSplitterMoved() {
    int nameAreaWidth = ui->headerSplitter->sizes().first();
    for(const auto entry : p->entryList) {
        entry->setNameAreaWidth(nameAreaWidth);
    }
}

void PropertyEditView::createEditEntryFor(const QMetaObject &metaObject)
{

}

